use std::{collections::HashMap, sync::Arc};
use tokio::sync::Mutex;

use axum::Router;
use tracing::{Level, info};
use tracing_subscriber::filter::EnvFilter;

use webauthn_rs::prelude::*;

pub mod config;

#[derive(Clone)]
pub struct AppState {
    pub webauthn: Arc<Webauthn>,
    pub users: Arc<Mutex<Data>>,
}

pub struct Data {
    pub name_to_id: HashMap<String, Uuid>,
    pub keys: HashMap<Uuid, Vec<Passkey>>,
}

impl AppState {
    pub fn new() -> Self {
        let rp_id = "localhost";
        // Url containing the effective domain name
        // MUST include the port number!
        let rp_origin = Url::parse("http://localhost:5173").expect("Invalid URL");
        let builder = WebauthnBuilder::new(rp_id, &rp_origin).expect("Invalid configuration");

        // Now, with the builder you can define other options.
        // Set a "nice" relying party name. Has no security properties and
        // may be changed in the future.
        let builder = builder.rp_name("Axum Webauthn-rs");

        // Consume the builder and create our webauthn instance.
        let webauthn = Arc::new(builder.build().expect("Invalid configuration"));

        let users = Arc::new(Mutex::new(Data {
            name_to_id: HashMap::new(),
            keys: HashMap::new(),
        }));

        Self { webauthn, users }
    }
}

#[derive(Debug)]
struct ServerState {
    version: &'static str,
    start_time: chrono::DateTime<chrono::Utc>,
}

pub fn init_logging() {
    tracing_subscriber::fmt()
        .with_target(false)
        .with_env_filter(EnvFilter::from_default_env().add_directive(Level::INFO.into()))
        .init();
}

fn print_startup_banner(addr: String) {
    info!("==============================================");
    info!(
        r#"
        _   (♥◠‿◠)ﾉﾞ  Axum启动成功   ლ(´ڡ`ლ)ﾞ
       / \   __  ___   _ _ __ ___  
      / _ \  \ \/ / | | | '_ ` _ \ 
     / ___ \  >  <| |_| | | | | | |
    /_/   \_\/_/\_\\__,_|_| |_| |_|
    
    🚀 服务地址: http://{}
    "#,
        addr
    );
    info!("==============================================");
}

pub async fn shutdown_signal() {
    tokio::signal::ctrl_c()
        .await
        .expect("无法注册CTRL+C处理程序");
    info!("收到关闭信号，开始优雅终止...");
}

pub async fn run_server(app: Router, addr: String) -> anyhow::Result<()> {
    let state = ServerState {
        version: env!("CARGO_PKG_VERSION"),
        start_time: chrono::Local::now().to_utc(),
    };

    // 绑定TCP端口
    let listener = tokio::net::TcpListener::bind(addr.clone())
        .await
        .map_err(|e| anyhow::anyhow!("绑定地址失败: {}", e))?;

    // 记录启动信息
    info!(
        address = addr,
        version = state.version,
        "🚀 开始启动服务器..."
    );

    // 启动服务器
    let server =
        axum::serve(listener, app.into_make_service()).with_graceful_shutdown(shutdown_signal());

    // 记录启动成功
    info!(
        uptime = format_args!("{:?}", chrono::Local::now().to_utc() - state.start_time),
        "🛡️ 服务器已就绪"
    );
    print_startup_banner(addr);

    server
        .await
        .map_err(|e| anyhow::anyhow!("服务器运行时错误: {}", e))?;

    Ok(())
}
